import {
  MiddlewareConsumer,
  Module,
  NestModule,
  RequestMethod,
} from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import ConfigModule from './config/config.module';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { ConfigService } from '@nestjs/config';
import { UserModule } from './modules/user/user.module';
import 'winston-daily-rotate-file';
// import logger from './core/middleware/logger.middleware';
import { utilities, WinstonModule } from 'nest-winston';
import * as winston from 'winston';
import 'winston-daily-rotate-file';
import { LoggerMiddleware } from './core/middleware/logger.middleware';
import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';
import { HttpExceptionFilter } from './core/filters/http-exception.filter';
import { ResponseInterceptor } from './core/interceptor/response.interceptor';
import * as process from 'process';
import { CacheModule } from '@nestjs/cache-manager';
import { redisStore } from 'cache-manager-redis-store';
import { RedisClientOptions } from 'redis';
import { ScheduleModule } from '@nestjs/schedule';
import { BullModule } from '@nestjs/bull';
import { MailerModule } from '@nestjs-modules/mailer';
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter';
import * as path from 'path';
import { ThrottlerModule, ThrottlerOptions } from '@nestjs/throttler';
import { TerminusModule } from '@nestjs/terminus';
import { HealthController } from './modules/health/health.controller';
import { HealthModule } from './modules/health/health.module';
import { AuthModule } from './modules/auth/auth.module';
import { JwtModule } from '@nestjs/jwt';
import { JwtMiddleware } from './core/middleware/jwt.middleware';
import { SysPostModule } from './modules/sys-post/sys-post.module';
import { SysUserModule } from './modules/sys-user/sys-user.module';
import { SysRoleModule } from './modules/sys-role/sys-role.module';
import { SysDeptModule } from './modules/sys-dept/sys-dept.module';
import { SystemModule } from './modules/system/system.module';
@Module({
  imports: [
    // 配置
    ConfigModule,
    // 数据库
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => {
        return {
          autoLoadEntities: true,
          keepConnectionAlive: true,
          ...config.get('database'),
        } as TypeOrmModuleOptions;
      },
    }),
    // 日志
    WinstonModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => {
        const format = winston.format.combine(
          winston.format.timestamp(),
          winston.format.json(),
        );
        return {
          format,
          transports: [
            // 写到文件
            new winston.transports.DailyRotateFile({
              ...config.get('log'),
            }),
            // 写到控制台
            process.env.NODE_ENV === 'development' &&
              new winston.transports.Console({
                // 字符串拼接
                format: winston.format.combine(
                  winston.format.timestamp(),
                  utilities.format.nestLike(),
                ),
              }),
          ],
        };
      },
    }),
    // 缓存
    CacheModule.registerAsync({
      isGlobal: true,
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => {
        return {
          store: redisStore,
          host: config.get('redis.host'),
          port: config.get('redis.port'),
          password: config.get('redis.password'),
          db: config.get('redis.db'),
        } as RedisClientOptions;
      },
    }),
    // 任务调度
    ScheduleModule.forRoot(),
    // 队列
    BullModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => {
        return {
          prefix: 'queue',
          redis: {
            host: config.get('redis.host'),
            port: config.get('redis.port'),
            password: config.get('redis.password'),
            db: config.get('redis.db'),
          },
        };
      },
    }),
    // 发送邮件
    MailerModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => {
        return {
          transport: {
            host: config.get('email.host'),
            port: config.get('email.port'),
            secure: config.get('email.secure'),
            auth: {
              user: config.get('email.auth.user'),
              pass: config.get('email.auth.pass'),
            },
          },
          template: {
            dir: path.join(__dirname, 'templates'),
            adapter: new HandlebarsAdapter(),
          },
        };
      },
    }),
    // 限流
    ThrottlerModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => {
        return {
          ttl: config.get('throttler.ttl'),
          limit: config.get('throttler.limit'),
        } as ThrottlerOptions as any;
      },
    }),
    // 健康检查
    TerminusModule,
    HealthModule,
    // jwt
    JwtModule.registerAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => {
        return {
          global: true,
          secret: config.get('jwt.secret'),
          signOptions: {
            expiresIn: config.get('jwt.expiresIn'),
          },
        };
      },
    }),
    UserModule,
    AuthModule,
    SysUserModule,
    SysPostModule,
    SysRoleModule,
    SysDeptModule,
    SystemModule,
  ],
  controllers: [AppController, HealthController],
  providers: [
    AppService,
    // 全局过滤异常
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter,
    },
    // 全局统一返回拦截器
    {
      provide: APP_INTERCEPTOR,
      useClass: ResponseInterceptor,
    },
    // 限流
    // {
    //   provide: APP_GUARD,
    //   useClass: ThrottlerGuard,
    // },
  ],
})
export class AppModule implements NestModule {
  // 应用全局中间件
  configure(consumer: MiddlewareConsumer) {
    const middlewares = [LoggerMiddleware, JwtMiddleware];
    consumer
      .apply(...middlewares)
      .forRoutes({ path: '*', method: RequestMethod.ALL });
  }
}
